package com.creative.xcx.service.Impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.creative.constant.Constants;
import com.creative.core.page.TableDataInfo;
import com.creative.core.uitls.Uidutil;
import com.creative.core.uitls.redis.CacheClient;
import com.creative.user.domain.UserInfo;
import com.creative.user.service.UserInfoService;
import com.creative.xcx.domain.MaterialType;
import com.creative.xcx.mapper.MaterialTypeMapper;
import com.creative.xcx.service.MaterialTypeService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.creative.constant.Constants.CACHE_NULL_TTL;
import static com.creative.constant.Constants.COMMON_PAGE_DATA_TTL;

/**
 * @author ling
 * @description 素材分类类型
 * @date 2025-02-26
 */
@Service
public class MaterialTypeServiceImpl implements MaterialTypeService {
    public static final Log logger = LogFactory.get();
    @Resource
    private MaterialTypeMapper materialTypeMapper;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private CacheClient cacheClient;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Integer insert(MaterialType materialType) {
        //        获取用户信息
        UserInfo userInfo = userInfoService.selectById((String) StpUtil.getLoginId());
        //      随机生成uid (15位以内)
        String id = Uidutil.generateUid(15);
        // 设置主键
        materialType.setTypeId(id);
        materialType.setCreateBy(userInfo.getNickName());
        materialType.setCreateTime(DateUtil.date());
        materialType.setPublishTime(DateUtil.date());
        materialType.setUpdateTime(DateUtil.date());

        return materialTypeMapper.insert(materialType);
    }

    @Override
    public Integer delete(String typeId) {
        if(materialTypeMapper.selectById(typeId) == null){
            return 0;
        }
        this.getMaterialTypeCache();
        return materialTypeMapper.delete(typeId);
    }


    @Override
    public Integer deleteBatch(String[] ids) {
        this.getMaterialTypeCache();
        return materialTypeMapper.deleteBatch(ids);
    }


    @Override
    public Integer update(MaterialType materialType) {
        this.getMaterialTypeCache();
        materialType.setUpdateTime(DateUtil.date());
        materialType.setUpdateBy(userInfoService.selectById((String) StpUtil.getLoginId()).getNickName());
        return materialTypeMapper.update(materialType);
    }

    @Override
    public MaterialType selectById(String typeId) {
        return materialTypeMapper.selectById(typeId);
    }

    @Override
    public TableDataInfo selectMaterialTypeList(MaterialType materialType) {
        PageHelper.startPage(materialType.getPageNum(), materialType.getPageSize(),"create_time desc");
        List<MaterialType> list = materialTypeMapper.selectMaterialTypeList(materialType);
        Page<MaterialType> page = (Page<MaterialType>) list;
//        转换为vo,使用page.getResult()进行转换
//    构建返回结果
        TableDataInfo tableDataInfo = new TableDataInfo();
        tableDataInfo.setMsg("查询成功");
        tableDataInfo.setCode(200);
//        设置返回类型结果
        tableDataInfo.setRows(page.getResult());
        tableDataInfo.setTotal(page.getTotal());
        return tableDataInfo;
    }

    @Override
    public List<MaterialType> selectMpMaterialTypeList(MaterialType materialType) {
        return this.getMaterialTypeCache();
    }

    /**
     * 获取素材类型缓存，同时更新缓存
     *
     * @return {@link List }<{@link MaterialType }>
     * @author ling
     * @date 2025/03/18
     */
    public List<MaterialType> getMaterialTypeCache() {
        MaterialType materialType = new MaterialType();
        materialType.setStatus(0);
        materialType.setDelFlag(0);

        String key = Constants.CACHE_MATERIAL_TYPE_KEY;
        // 1.查询缓存
        String json = stringRedisTemplate.opsForValue().get(key);
        // 处理缓存命中
        if (StrUtil.isNotBlank(json)) {
            logger.info("命中缓存 key: {}", key);
            // 使用安全反序列化方法
            return parseJsonSafely(json, key);
        }

        // 处理空值缓存（防止缓存穿透）
        if (StrUtil.EMPTY.equals(json)) {
            logger.info("命中空值缓存 key: {}", key);
            return Collections.emptyList();
        }
        /// 2. 缓存未命中，查询数据库
        List<MaterialType> list = materialTypeMapper.selectMaterialTypeList(materialType);

        // 3. 处理空结果（防止缓存穿透）
        if (CollUtil.isEmpty(list)) {
            logger.warn("空结果缓存 key: {}", key);
            // 设置短时间空值缓存（5分钟）
            stringRedisTemplate.opsForValue().set(
                    key,
                    StrUtil.EMPTY,
                    CACHE_NULL_TTL,
                    TimeUnit.MINUTES
            );
            return Collections.emptyList();
        }

        // 4. 写入正常缓存
        try {
            cacheClient.set(
                    key,
                    list,  // 直接传递集合对象
                    COMMON_PAGE_DATA_TTL,
                    TimeUnit.HOURS
            );
            logger.info("更新缓存成功 key: {}", key);
        } catch (Exception e) {
            logger.error("缓存写入失败 key: {}", key, e);
            throw new RuntimeException("小程序获取素材类型异常", e);
        }
        return list;
    }

    // 安全的JSON反序列化方法
    private List<MaterialType> parseJsonSafely(String json, String key) {
        try {
            return JSONUtil.toList(json, MaterialType.class);
        } catch (Exception e) {
            logger.error("JSON反序列化失败 json: {}", json, e);
            // 清除无效缓存
            stringRedisTemplate.delete(key);
            return Collections.emptyList();
        }
    }

    @Override
    public List<MaterialType> exportBatch(String[] ids) {
        return materialTypeMapper.exportBatch(ids);
    }

    @Override
    public List<MaterialType> selectTypeList() {
        return materialTypeMapper.selectTypeList();
    }

    @Override
    public Long calculateMaterialType() {
        return materialTypeMapper.calculateMaterialType();
    }


}
